package stone926.mods.more_enchantments.mixins;

import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.projectile.FireworkRocketEntity;
import net.minecraft.entity.projectile.ProjectileEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import stone926.mods.more_enchantments.MoreEnchantmentsMod;
import stone926.mods.more_enchantments.enchantments.HoverEnchantment;
import stone926.mods.more_enchantments.enchantments.ReinforcedGunpowderEnchantment;
import stone926.mods.more_enchantments.interfaces.ILivingEntity;
import stone926.mods.more_enchantments.interfaces.IRocketReinforced;
import stone926.mods.more_enchantments.util.RandomUtil;

import static stone926.mods.more_enchantments.nbt.CustomNbtKeys.FIREWORK_ROCKET.EXTRA_DAMAGE;

@Mixin(FireworkRocketEntity.class)
public abstract class FireworkRocketEntityMixin extends Entity implements IRocketReinforced {

  private static final String MOD_ID = MoreEnchantmentsMod.MOD_ID + ":";
  private double extraDamage;
  @Shadow
  @Nullable
  private LivingEntity shooter;

  public FireworkRocketEntityMixin(EntityType<?> type, World world) {
    super(type, world);
  }

  @Shadow
  public abstract ItemStack getStack();

  @Override
  public double getExtraDamage() {
    return extraDamage;
  }

  @Override
  public void setExtraDamage(double extraDamage) {
    this.extraDamage = extraDamage;
  }

  @Inject(method = "readCustomDataFromNbt", at = @At("HEAD"))
  private void readCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {
    if (nbt.contains(EXTRA_DAMAGE)) setExtraDamage(nbt.getDouble(EXTRA_DAMAGE));
  }

  @Inject(method = "writeCustomDataToNbt", at = @At("HEAD"))
  private void writeCustomDataToNbt(NbtCompound nbt, CallbackInfo ci) {
    nbt.putDouble(EXTRA_DAMAGE, getExtraDamage());
  }

  @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;setVelocity(Lnet/minecraft/util/math/Vec3d;)V"))
  private void handleHoverEnchantment(LivingEntity shooter, Vec3d velocity) {
    ItemStack selfStack = getStack();
    int hoverLvl = EnchantmentHelper.getLevel(MoreEnchantmentsMod.HOVER, selfStack);
    if (hoverLvl > 0) {
      double multiplier = HoverEnchantment.getVelocityMultiplier(hoverLvl);
      Vec3d rotationVector = shooter.getRotationVector();
      Vec3d shooterVelocity = shooter.getVelocity();
      shooter.setVelocity(shooterVelocity.add(
        rotationVector.x * 0.1D + (rotationVector.x * 1.5D - shooterVelocity.x) * (0.5D + multiplier),
        rotationVector.y * 0.1D + (rotationVector.y * 1.5D - shooterVelocity.y) * (0.5D + multiplier),
        rotationVector.z * 0.1D + (rotationVector.z * 1.5D - shooterVelocity.z) * (0.5D + multiplier)
      ));
    } else {
      shooter.setVelocity(velocity);
    }
  }

  @Redirect(method = "explode", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;damage(Lnet/minecraft/entity/damage/DamageSource;F)Z"))
  private boolean redirectDamage(LivingEntity livingEntity, DamageSource source, float amount) {
    int reinforcedGunpowderLvl = EnchantmentHelper.getLevel(MoreEnchantmentsMod.REINFORCED_GUNPOWDER, getStack());
    if (reinforcedGunpowderLvl > 0) {
      amount += ReinforcedGunpowderEnchantment.getExtraDamage(reinforcedGunpowderLvl);
    }
    if (livingEntity.equals(((ProjectileEntity) (Object) this).getOwner()) && RandomUtil.isPossible(reinforcedGunpowderLvl * 0.35, random)) {
      return false;
    } else {
      return RandomUtil.isPossible(reinforcedGunpowderLvl * 0.18, random) ?
        ((ILivingEntity) livingEntity).forceDamage(source, amount) :
        livingEntity.damage(source, amount);
    }
  }

}
